#pragma once

#include <iostream>
#include <functional>
#include <jsoncpp/json/json.h>
#include "Socket.hpp"
#include "Log.hpp"

using namespace std;
using namespace LogModule;
using namespace SocketModule;

class Request // client->server   
{
public:
    Request(int x = 0, int y = 0, char oper = '\0')
        : _x(x), _y(y), _oper(oper)
    {
    }

    string Serialize()
    {
        Json::Value root;
        root["x"] = _x;
        root["y"] = _y;
        root["oper"] = _oper;
        Json::FastWriter write;
        string s = write.write(root);
        return s;
    }

    bool Deserialize(string &in)
    {
        Json::Value root;
        Json::Reader reader;
        bool ok = reader.parse(in, root);
        if (ok)
        {
            _x = root["x"].asInt();
            _y = root["y"].asInt();
            _oper = root["oper"].asInt();
        }
        return true;
    }

    ~Request()
    {
    }

    int X() { return _x; }
    int Y() { return _y; }
    int Oper() { return _oper; }

private:
    int _x;
    int _y;
    char _oper;
};

class Response // server->client    
{
public:
    Response() : _result(0), _code(0) {}
    Response(int result, int code)
        : _result(result), _code(code)
    {
    }
    string Serialize()
    {
        Json::Value root;
        root["result"] = _result;
        root["code"] = _code;
        Json::FastWriter writer;
        string s = writer.write(root);
        return s;
    }
    bool Deserialize(string &in)
    {
        Json::Value root;
        Json::Reader reader;
        bool ok = reader.parse(in, root);
        if (ok)
        {
            _result = root["result"].asInt();
            _code = root["code"].asInt();
        }
        return true;
    }
    ~Response()
    {
    }
    void SetResult(int res)
    {
        _result = res;
    }
    void SetCode(int code)
    {
        _code = code;
    }
    void ShowResult()
    {
        cout << "计算结果是: " << _result << "[" << _code << "]" << endl;
    }

private:
    int _result;
    int _code;
};

const string sep = "\r\n";
using punc_t = function<Response(Request &req)>;
class Protocol
{
public:
    Protocol()
    {
    }

    Protocol(punc_t punc)
        : _punc(punc)
    {
    }

    // 封装报头
    string Encode(const string &jsonstr) // 50\r\n{"x": 10, "y" : 20, "oper" : '+'}\r\n
    {
        string len = to_string(jsonstr.size());
        return len + sep + jsonstr + sep;
    }
    // 解析
    bool Decode(string &buffer, string *package)
    {
        ssize_t pos = buffer.find(sep);
        if (pos == string::npos)
        {
            return false;
        }
        string package_len_str = buffer.substr(0, pos);                            //"50"
        int package_len_int = stoi(package_len_str);                               // 50
        int targt_len = package_len_str.size() + package_len_int + 2 * sep.size(); // 整个封装后数据的长度
        if (buffer.size() < targt_len)
        {
            return false;
        }
        *package = buffer.substr(pos + sep.size(), package_len_int); // 去掉封装的报文
        buffer.erase(0, targt_len);
        return true;
    }

    string Execute(string &package)
    {
        LOG(LogLevel::DEBUG) << "进入到protocol Execute begnin";


        Request req;
        bool ok = req.Deserialize(package);
        if (!ok)
            return std::string();
        Response resp = _punc(req);

        // 序列化
        std::string json_str = resp.Serialize();

        // 添加自定义长度
        std::string send_str = Encode(json_str); // 携带长度的应答报文了"len\r\n{result:XXX, code:XX}\r\n"

        LOG(LogLevel::DEBUG) << "进入到protocol Execute end";

        // 返回运算结果
        return send_str;
    }

    string BuildRequestString(int x, int y, char oper)
    {
        Request req(x, y, oper);           // 创建进行序列化的对象
        string json_req = req.Serialize(); // 序列化
        return Encode(json_req);           // 封装报文
    }

    bool GetResponse(shared_ptr<Socket> &client, string &resp_buff, Response *resp)
    {
        while (true)
        {
            int n = client->Recv(&resp_buff);
            if (n > 0)
            {
                string json_package;

                while (Decode(resp_buff, &json_package))
                {
                    resp->Deserialize(json_package);
                }
                return true;
            }
            else if (n == 0)
            {
                std::cout << "server quit " << std::endl;
                return false;
            }
            else
            {
                std::cout << "recv error" << std::endl;
                return false;
            }
        }
    }
    ~Protocol()
    {
    }

private:
    punc_t _punc;
};